package com.opencee.cloud.api.gateway.locator;

import com.alibaba.cloud.dubbo.env.DubboCloudProperties;
import com.opencee.common.utils.RedisTemplateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import reactor.core.publisher.Mono;


/**
 * 自定义动态路由加载器
 *
 * @author liuyadu
 */
@Slf4j
public class ApiRouteLocator implements InitializingBean, ApplicationEventPublisherAware {
    private RedisTemplateUtil redisTemplateUtil;
    private ApplicationEventPublisher publisher;
    private RouteDefinitionRepository repository;

    private DubboCloudProperties dubboCloudProperties;

    public ApiRouteLocator(RedisTemplateUtil redisUtil, RouteDefinitionRepository repository, DubboCloudProperties dubboCloudProperties) {
        this.redisTemplateUtil = redisUtil;
        this.repository = repository;
        this.dubboCloudProperties = dubboCloudProperties;
    }

    /**
     * 刷新路由
     *
     * @return
     */
    public Mono<Void> refresh() {
        this.loadRoutes();
        // 触发默认路由刷新事件,刷新缓存路由
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return Mono.empty();
    }

    private Mono<Void> loadRoutes() {
     /*   try {
            // redis中读取
            Map<String, Object> routerMap = redisUtil.getMap(GatewayConstants.API_ROUTER_RELEASE);
            List<GatewayRouteDefinition> routeDefinitionList = new ArrayList<>();
            if (routerMap != null && !routerMap.isEmpty()) {
                Iterator<Map.Entry<String, Object>> iterable = routerMap.entrySet().iterator();
                while (iterable.hasNext()) {
                    Map.Entry<String, Object> entry = iterable.next();
                    GatewayRouteDefinition definition = new GatewayRouteDefinition();
                    OpenApiRelease apiRouter = (OpenApiRelease) entry.getValue();
                    definition.setId(apiRouter.getReleaseId().toString());
                    BeanUtil.copyProperties(apiRouter, definition);
                    routeDefinitionList.add(definition);
                }
            }
            if (routeDefinitionList != null) {
                Set<String> subscribedServices = new HashSet<>();
                routeDefinitionList.forEach(r -> {
                    if (ServerProtocol.DUBBO.name().equals(r.getServerProtocol())) {
                        // Dubbo订阅的服务列表
                        subscribedServices.add(r.getServerName());
                    }
                    Map<String, Object> metadata = r.getMetadata();
                    JSONObject routerDefinition = (JSONObject) metadata.get("routerDefinition");
                    String url = routerDefinition.getString("url");
                    List<PredicateDefinition> predicates = JSONObject.parseArray(routerDefinition.getString("predicates"), PredicateDefinition.class);
                    List<FilterDefinition> filters = JSONObject.parseArray(routerDefinition.getString("filters"), FilterDefinition.class);
                    r.setPredicates(predicates);
                    r.setFilters(filters);
                    r.setUri(UriComponentsBuilder.fromUriString(url).build().toUri());
                    this.repository.save(Mono.just(r)).subscribe();
                });
                publisher.publishEvent(new SubscribedServicesChangedEvent(this, dubboCloudProperties.subscribedServices(), subscribedServices));
                log.info("=============加载动态路由:{}==============", routeDefinitionList.size());
            }
        } catch (Exception e) {
            log.error("加载动态路由错误:{}", e);
        }*/
        return Mono.empty();
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        loadRoutes();
    }
}
